/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2009>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.OleDb;
using System.Data;
using System.IO;
using MyPhotoIndex.Utilities.Types;
using MyPhotoIndex.Controls.TagTree;
using System.Runtime.Serialization.Formatters.Binary;
using MyPhotoIndex.DataAccess;
using MyPhotoIndex.Interfaces;
using MyPhotoIndex.Utilities;
using MyPhotoIndex.ImageBank;
using System.Globalization;
using MyPhotoIndex.Interfaces.Tagging;
using MyPhotoIndex.Settings;

namespace MyPhotoIndex.Importer
{
    class ImportTag
    {
        public String Name;
        public int Id;
        public int newId;
        public int ParentId;
        public List<ImportTag> Children = new List<ImportTag>();
        public ImportTag Parent;
    }

    class ImaportedImage
    {
        public String FileName;
        public String Caption;
        public List<int> Tags = new List<int>();
    }

    public class PSE3Importer : ImageDataImporter
    {
        private String m_psaFilename;
        private DataSet m_myDataSet = new DataSet();
        private DataView m_myDataView = new DataView();
        private DataSet m_versionData = new DataSet();
        private DataView m_versionDataView = new DataView();
        private DataSet m_pageData = new DataSet();
        private DataView m_pageDataView = new DataView();
        private DataView m_imageDatatView = new DataView();
        private OleDbConnection m_dbConnection;

        private bool m_version;

        List<ImportTag> m_tags = new List<ImportTag>();
        Dictionary<String, ImaportedImage> m_images = new Dictionary<String,ImaportedImage>();
        List<IImageTag> m_storedtags;
        IImageTagCollection m_tagFactory;

        public PSE3Importer():
            base(Guid.NewGuid().ToString())
        {
         
        }

        public void Import(String pseFileName, bool importTags)
        {
            m_psaFilename = pseFileName;

            LoadTagDB();
            ImportTagsTree();
            GenerateImageTagListPSA();
            base.Import(ApplicationSettings.Default.CachedThumbnailSize);
        }

        public void LoadTagDB()
        {
            String connetionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + m_psaFilename;
            String versionQueryString = "SELECT fVerNeededToReadF3 FROM IdTable";
            String folderTableQuery = "SELECT fFolderId, fFolderName, fParentFolderId, fFirstChildFolderId, fFolderAttributes, fFirstPageId, fNextFolderId FROM FolderTable WHERE ((fFolderAttributes < 720896) AND ((fFolderAttributes < 589824) OR (fFolderAttributes > 655360)))";
            
            DataSet set1 = new DataSet();
            DataView view1 = new DataView();
            DataSet set2 = new DataSet();
            try
            {
                m_dbConnection = new OleDbConnection(connetionString);
            }
            catch (Exception exception1)
            {
                Logger.Log(exception1);
                return;
            }

            try
            {
                OleDbCommand command1 = new OleDbCommand(versionQueryString, m_dbConnection);
                OleDbDataAdapter adapter1 = new OleDbDataAdapter(command1);
                m_dbConnection.Open();
                adapter1.Fill(set1, "IdTable");
                view1.Table = set1.Tables["IdTable"];
                int num1 = Convert.ToInt32(view1[0]["fVerNeededToReadF3"]);
                if (num1 < 0x27)
                {
                    this.m_version = true;
                }
                else
                {
                    this.m_version = false;
                }
            }
            catch (Exception exception2)
            {
                Logger.Log(exception2);

                return;
            }

            try
            {
                String imageTableQuery;
                if (this.m_version)
                {
                    imageTableQuery = "SELECT fImageId, fImageAttributes, fFolderInfoArray, fMediaFullPath, fMediaEditedFullPath,fImageCaption,fImageOriginalFileName, fImageTime FROM ImageTable WHERE (fMediaProxyPathIdFromMedia = 0) AND ((fImageAttributes = 0) OR (fImageAttributes = 16) OR (fImageAttributes = 32))";
                }
                else
                {
                    imageTableQuery = "SELECT fImageId, fImageAttributes, fFolderInfoArray, fMediaFullPath, fVersionSetParentId,fMediaShortCaptionIdFromMedia, fImageTime,fImageOriginalFileName FROM ImageTable WHERE (fMediaProxyPathIdFromMedia = 0) AND ((fImageAttributes = 0) OR (fImageAttributes = 16) OR (fImageAttributes = 32))";
                }

                OleDbCommand command2 = new OleDbCommand(folderTableQuery, m_dbConnection);
                OleDbDataAdapter adapter2 = new OleDbDataAdapter(command2);
                OleDbCommand command3 = new OleDbCommand(imageTableQuery, m_dbConnection);
                OleDbDataAdapter adapter3 = new OleDbDataAdapter(command3);
                adapter2.Fill(this.m_myDataSet, "FolderTable");
                adapter3.Fill(set2, "ImageTable");
 
                m_imageDatatView.Table = set2.Tables["ImageTable"];
                this.m_myDataView.Table = this.m_myDataSet.Tables["FolderTable"];
                if (!this.m_version)
                {
                    String text5 = "SELECT fFolderId, fFolderAttributes FROM FolderTable WHERE (fFolderAttributes > 524288)";
                    OleDbCommand command4 = new OleDbCommand(text5, m_dbConnection);
                    new OleDbDataAdapter(command4).Fill(this.m_versionData, "FolderTable");
                    this.m_versionDataView.Table = this.m_versionData.Tables["FolderTable"];
                    String text6 = "SELECT fPageId,fFolderIdFromPage,fImageIdFromPage,fNextPageId FROM PageTable";
                    OleDbCommand command5 = new OleDbCommand(text6, m_dbConnection);
                    new OleDbDataAdapter(command5).Fill(this.m_pageData, "PageTable");
                    this.m_pageDataView.Table = this.m_pageData.Tables["PageTable"];
                }
            }
            catch (Exception exception3)
            {
                Logger.Log(exception3);
                return;
            }
            finally
            {
                m_dbConnection.Close();
            }
        }

        private void ImportTagsTree()
        {
            m_tagFactory = ImageTagCollection.Instance;
            m_storedtags = m_tagFactory.Tags;

            foreach (DataRowView row in m_myDataView)
            {
                int parentId = (int)row["fParentFolderId"];
                int id = (int)row["fFolderId"];
                String name = (String)row["fFolderName"];

                if (parentId == 0 &&
                    String.IsNullOrEmpty(name) == false)
                {
                    ImportTag importTag = new ImportTag();
                    importTag.Id = id;
                    importTag.ParentId = parentId;
                    importTag.Name = name;

                    ImportTagsTree(importTag);

                    m_tags.Add(importTag);
                }
            }

            ImageTag dummyParent = new ImageTag();
            dummyParent.Id = -1;

            foreach (ImportTag tag in m_tags)
            {
                AddTag(tag, dummyParent);
            }
        }

        private void ImportTagsTree(ImportTag parentTag)
        {
            foreach (DataRowView row in m_myDataView)
            {
                int parentId = (int)row["fParentFolderId"];
                int id = (int)row["fFolderId"];
                String name = (String)row["fFolderName"];

                if (parentTag.Id == parentId &&
                    String.IsNullOrEmpty(name) == false)
                {
                    ImportTag newTag = new ImportTag();
                    newTag.Id = id;
                    newTag.ParentId = parentId;
                    newTag.Name = name;
                    newTag.Parent = parentTag;
                    parentTag.Children.Add(newTag);

                    ImportTagsTree(newTag);
                }
            }
        }

        private void AddTag(ImportTag importTag, IImageTag parent)
        {
            IImageTag newTag = GetTagByName(importTag.Name, m_storedtags);
            if (newTag == null)
            {
                newTag = new ImageTag();
                newTag.Name = importTag.Name;
                newTag.Description = importTag.Name;
                newTag.Parent = parent;
                m_tagFactory.SaveTag(newTag);
            }

            importTag.newId = newTag.Id;
            foreach (ImportTag childTag in importTag.Children)
            {
                AddTag(childTag, newTag);
            }
        }

        private IImageTag GetTagByName(String name, List<IImageTag> tags)
        {
            IImageTag newTag = null;
            foreach (ImageTag tag in tags)
            {
                if (String.Compare(tag.Name, name, true, CultureInfo.InvariantCulture) == 0)
                {
                    newTag = tag;
                    break;
                }

                if (newTag == null)
                {
                    newTag = GetTagByName(name, tag.ChildTags);
                    if (newTag != null)
                    {
                        break;
                    }
                }
            }

            return newTag;
        }

        private ImportTag GetTagById(int id, List<ImportTag> tags)
        {
            ImportTag foundTag = null;
            foreach (ImportTag tag in tags)
            {
                if (tag.Id == id)
                {
                    foundTag = tag;
                    break;
                }

                if (foundTag == null)
                {
                    foundTag = GetTagById(id, tag.Children);
                    if (foundTag != null)
                    {
                        break;
                    }
                }
            }

            return foundTag;
        }

        private void GenerateImageTagListPSA()
        {
            for (int num2 = 0; num2 < m_imageDatatView.Count; num2++)
            {
                String  imageFileName;
                String  imageCaption = String.Empty;
                bool    isLastImageVersion = false;

                byte[] buffer1 = (byte[])m_imageDatatView[num2]["fFolderInfoArray"];
                if (this.m_version)
                {
                    imageFileName = Convert.ToString(m_imageDatatView[num2]["fMediaEditedFullPath"]);
                    if (((Convert.ToInt16(imageFileName[0]) == 0) || (imageFileName == null)) || ((imageFileName == "") || (imageFileName.Length == 0)))
                    {
                        imageFileName = (String)m_imageDatatView[num2]["fMediaFullPath"];
                    }

                    imageCaption = Convert.ToString(m_imageDatatView[num2]["fImageCaption"]);
                    isLastImageVersion = true;
                }
                else
                {
                    if (Convert.ToInt32(m_imageDatatView[num2]["fMediaShortCaptionIdFromMedia"]) != 0)
                    {
                        int num7 = Convert.ToInt32(m_imageDatatView[num2]["fMediaShortCaptionIdFromMedia"]);
                        imageCaption = this.GetCaption(num7.ToString());
                    }

                    isLastImageVersion = this.IsLatestVersion(m_imageDatatView[num2]);
                    imageFileName = Convert.ToString(m_imageDatatView[num2]["fMediaFullPath"]);
                }

                if (imageFileName.EndsWith("\0"))
                {
                    imageFileName = imageFileName.Substring(0, imageFileName.Length - 1);
                }

                if (isLastImageVersion)
                {
                    int fileId = (int)m_imageDatatView[num2]["fImageID"];

                    List<int> tagIds = new List<int>();
                    for (int num3 = 0; num3 < buffer1.Length; num3 += 4)
                    {
                        uint num4 = (uint)(buffer1[num3] | (buffer1[num3 + 1] << 8));
                        uint num5 = (uint)(buffer1[num3 + 2] | (buffer1[num3 + 3] << 8));
                        int num6 = (int)(num4 | (num5 << 0x10));
                        if (num6 == 0)
                        {
                            break;
                        }

                        tagIds.Add(num6);
                    }

                    ImaportedImage importedImage = new ImaportedImage();
                    importedImage.FileName = imageFileName;
                    importedImage.Caption = imageCaption;
                    importedImage.Tags.AddRange(tagIds);
                    m_images.Add(importedImage.FileName, importedImage);
                    FileList.Add(importedImage.FileName);

                 //   this.progress.Progress(((int)((((float)num2) / ((float)m_imageDatatView.Count)) * 50f)) + 50, text3);
                }
            }
        }

        //protected override byte[] GetImageTagInfo(String fileName)
        //{
        //    ImaportedImage importedImage = m_images[fileName];
        //    if (importedImage == null)
        //    {
        //        return new byte[] { };
        //    }

        //    List<int> newTagIds = null;
        //    if (m_tags.Count > 0)
        //    {
        //        newTagIds = new List<int>();
        //        foreach (int tagId in importedImage.Tags)
        //        {
        //            ImportTag tag = GetTagById(tagId, m_tags);
        //            if (tag != null)
        //            {
        //                newTagIds.Add(tag.newId);
        //            }
        //        }
        //    }
        //    else
        //    {
        //        newTagIds = importedImage.Tags;
        //    }

        //    byte[] tagBytes = null;

        //    using (MemoryStream ms = new MemoryStream())
        //    {
        //        BinaryFormatter bf = new BinaryFormatter();
        //        bf.Serialize(ms, newTagIds.ToArray());
        //        tagBytes = ms.ToArray();
        //    }

        //    return tagBytes;
        //}

        private String GetCaption(String id)
        {
            String text1 = "SELECT fMediaShortCaption FROM MediaShortCaptionTable WHERE fMediaShortCaptionId = " + id;
            OleDbCommand command1 = new OleDbCommand(text1, m_dbConnection);
            OleDbDataAdapter adapter1 = new OleDbDataAdapter(command1);
            DataSet set1 = new DataSet();
            DataView view1 = new DataView();
            adapter1.Fill(set1, "MediaShortCaptionTable");
            view1.Table = set1.Tables["MediaShortCaptionTable"];
            return view1[0]["fMediaShortCaption"].ToString();
        }

        private bool IsLatestVersion(DataRowView image)
        {
            bool tag1 = false;
            bool tag2 = false;
            bool tag3 = false;
            this.m_pageDataView.RowFilter = "fImageIdFromPage = " + image["fImageId"].ToString();
            if (this.m_pageDataView.Count == 0)
            {
                return true;
            }
            for (int num2 = 0; num2 < this.m_pageDataView.Count; num2++)
            {
                this.m_versionDataView.RowFilter = "fFolderId = " + this.m_pageDataView[num2]["fFolderIdFromPage"];
                this.m_pageDataView.RowFilter = "fNextPageId = " + Convert.ToInt32(this.m_pageDataView[num2]["fPageId"], CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture);
                if (this.m_versionDataView.Count != 0)
                {
                    int num1 = Convert.ToInt32(this.m_versionDataView[0]["fFolderAttributes"]) & 0xff0000;
                    switch (num1)
                    {
                        case 0x80000:
                            tag3 = true;
                            break;

                        case 0x100000:
                            if ((this.m_pageDataView.Count == 0) && !tag1)
                            {
                                tag2 = true;
                            }
                            goto Label_0120;
                    }
                    if (num1 == 0x120000)
                    {
                        if (this.m_pageDataView.Count == 0)
                        {
                            tag1 = true;
                        }
                        else
                        {
                            tag2 = false;
                        }
                    }
                }
            Label_0120:
                this.m_pageDataView.RowFilter = "fImageIdFromPage = " + image["fImageId"].ToString();
            }
            return ((tag3 | tag1) | tag2);
        }
    }
}
